package remotesaver;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;

import masterserver.MasterServer;

import shared.CloudException;
import shared.Constants;
import shared.DataChunk;
import shared.MasterServerInterface;
import shared.RemoteSaverInterface;

public class RemoteSaver extends java.rmi.server.UnicastRemoteObject implements
	RemoteSaverInterface
{

    public RemoteSaver() throws RemoteException
    {
	super(Constants.REMOTE_SAVER_PORT);
    }

    @Override
    public void remoteSaveFile(DataChunk dataChunk, String filename)
	    throws CloudException
    {
	this.purgeStore();

	Path pathname = Paths.get(filename);
	if (!Files.exists(pathname))
	    try
	    {
		Files.createFile(pathname);
	    } catch (IOException e)
	    {
		e.printStackTrace();
	    }

	SeekableByteChannel channel = null;
	try
	{
	    channel = Files.newByteChannel(pathname,
		    java.nio.file.StandardOpenOption.WRITE);
	    channel.position(dataChunk.getOffset());
	    ByteBuffer writeBuffer = ByteBuffer.wrap(dataChunk.getContent());
	    int bytesWritten = channel.write(writeBuffer);

	    if (bytesWritten != dataChunk.getContent().length)
		throw new CloudException("Incomplete write! Failure!");

	    System.out.println("Successfully received one remote backup.");

	} catch (Exception e)
	{
	    e.printStackTrace();
	    throw new CloudException(e);
	} finally
	{
	    try
	    {
		channel.close();
	    } catch (IOException e)
	    {
		e.printStackTrace();
	    }
	}
    }

    public void purgeStore()
    {
	String[] names = new String[] { "files", "users", "dataservers", "logs" };

	for (int i = 0; i < names.length; i++)
	{
	    String folderName = Constants.MASTERSERVER_METAFILES_DIR + names[i]
		    + "/";
	    File folder = new File(folderName);
	    File[] listOfFiles = folder.listFiles();

	    ArrayList<Long> fileNums = new ArrayList<Long>();
	    for (File file : listOfFiles)
	    {
		try
		{
		    fileNums.add(Long.parseLong(file.getName()));
		} catch (Exception e)
		{
		    e.printStackTrace();
		}
	    }

	    // sort in ascending order..
	    java.util.Collections.sort(fileNums);
	    if (fileNums.size() > 5)
	    {
		Path pathToDelete = Paths.get(folderName + fileNums.get(0));
		try
		{
		    Files.delete(pathToDelete);
		} catch (IOException e)
		{
		    e.printStackTrace();
		}

	    }
	}
    }

    public static void main(String[] args)
    {

	if (args.length == 0)
	{
	    System.out.println("usage: java remotesaver.RemoteSaver serverNo.");
	    System.exit(-1);
	}

	int serverNo = 0;
	try
	{
	    serverNo = Integer.parseInt(args[0]);
	} catch (Exception e)
	{
	    System.out.println("serverNo. must be an integer!");
	    System.exit(-1);
	}

	String myHostname = null;
	switch (serverNo)
	{
	case 1:
	    myHostname = Constants.MASTER_SERVER_1_IP;
	    break;
	case 2:
	    myHostname = Constants.MASTER_SERVER_2_IP;
	    break;
	case 3:
	    myHostname = Constants.MASTER_SERVER_3_IP;
	    break;
	default:
	    myHostname = Constants.MASTER_SERVER_1_IP;
	    break;
	}

	System.setProperty("java.rmi.server.hostname", myHostname);

	RemoteSaverInterface myInterface = null;
	try
	{
	    myInterface = new RemoteSaver();
	} catch (Exception e)
	{
	    e.printStackTrace();
	    System.exit(1);
	}

	Registry registry = null;

	try
	{
	    // create the registry and bind the name and object.
	    registry = LocateRegistry.createRegistry(Constants.REGISTRY_PORT);
	    registry.rebind(Constants.REMOTE_SAVER_NAME, myInterface);
	} catch (RemoteException e)
	{
	    System.out.println(e.getMessage());
	}

	System.out.println("RemoteSaver ready!!");

    }

}
